/*
 * This file is part of aion-lightning <aion-lightning.org>
 *
 * aion-lightning is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aion-lightning is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with aion-lightning. If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionengine.gameserver.model.instance.instancereward;

import com.aionemu.commons.utils.Rnd;
import com.aionengine.gameserver.model.gameobjects.player.Player;
import com.aionengine.gameserver.model.instance.instanceposition.*;
import com.aionengine.gameserver.model.instance.playerreward.PvPArenaPlayerReward;
import com.aionengine.gameserver.network.aion.serverpackets.SM_INSTANCE_SCORE;
import com.aionengine.gameserver.utils.PacketSendUtility;
import com.aionengine.gameserver.world.WorldMapInstance;
import com.aionengine.gameserver.world.knownlist.Visitor;
import javolution.util.FastList;

import java.util.*;

import static ch.lambdaj.Lambda.*;

/**
 * @author xTz
 */
public class PvPArenaReward extends InstanceReward<PvPArenaPlayerReward> {

    private Map<Integer, Boolean> positions = new HashMap<Integer, Boolean>();
    private FastList<Integer> zones = new FastList<Integer>();
    private int round = 1;
    private Integer zone;
    private int bonusTime;
    private int capPoints;
    private long instanceTime;
    private final byte buffId;
    protected WorldMapInstance instance;
    private GenerealInstancePosition instancePosition;

    public PvPArenaReward(Integer mapId, int instanceId, WorldMapInstance instance) {
        super(mapId, instanceId);
        this.instance = instance;
        boolean isSolo = isSoloArena();
        capPoints = isSolo ? 14400 : 50000;
        bonusTime = isSolo ? 8100 : 12000;
        Collections.addAll(zones, isSolo ? new Integer[]{1, 2, 3, 4}
                : new Integer[]{1, 2, 3, 4, 5, 6});
        int positionSize;
        if (isSolo) {
            positionSize = 4;
            buffId = 8;
            instancePosition = new DisciplineInstancePosition();
        } else if (isGlory()) {
            buffId = 7;
            positionSize = 8;
            instancePosition = new GloryInstancePosition();
        } else if (mapId == 300450000 || mapId == 300570000) {
            buffId = 7;
            positionSize = 12;
            instancePosition = new HarmonyInstancePosition();
        } else {
            buffId = 7;
            positionSize = 12;
            instancePosition = new ChaosInstancePosition();
        }
        instancePosition.initsialize(mapId, instanceId);
        for (int i = 1; i <= positionSize; i++) {
            positions.put(i, Boolean.FALSE);
        }
        setRndZone();
    }

    public final boolean isSoloArena() {
        return mapId == 300430000 || mapId == 300360000;
    }

    public final boolean isGlory() {
        return mapId == 300550000;
    }

    public int getCapPoints() {
        return capPoints;
    }

    public final void setRndZone() {
        int index = Rnd.get(zones.size());
        zone = zones.get(index);
        zones.remove(index);
    }

    private List<Integer> getFreePositions() {
        List<Integer> p = new ArrayList<Integer>();
        for (Integer key : positions.keySet()) {
            if (!positions.get(key)) {
                p.add(key);
            }
        }
        return p;
    }

    public synchronized void setRndPosition(Integer object) {
        PvPArenaPlayerReward reward = getPlayerReward(object);
        int position = reward.getPosition();
        if (position != 0) {
            clearPosition(position, Boolean.FALSE);
        }
        Integer key = getFreePositions().get(Rnd.get(getFreePositions().size()));
        clearPosition(key, Boolean.TRUE);
        reward.setPosition(key);
    }

    public synchronized void clearPosition(int position, Boolean result) {
        positions.put(position, result);
    }

    public int getRound() {
        return round;
    }

    public void setRound(int round) {
        this.round = round;
    }

    public void regPlayerReward(Integer object) {
        if (!containPlayer(object)) {
            addPlayerReward(new PvPArenaPlayerReward(object, bonusTime, buffId));
        }
    }

    @Override
    public void addPlayerReward(PvPArenaPlayerReward reward) {
        super.addPlayerReward(reward);
    }

    @Override
    public PvPArenaPlayerReward getPlayerReward(Integer object) {
        return (PvPArenaPlayerReward) super.getPlayerReward(object);
    }

    public void portToPosition(Player player) {
        Integer object = player.getObjectId();
        regPlayerReward(object);
        setRndPosition(object);
        PvPArenaPlayerReward playerReward = getPlayerReward(object);
        playerReward.applyBoostMoraleEffect(player);
        instancePosition.port(player, zone, playerReward.getPosition());
    }

    public List<PvPArenaPlayerReward> sortPoints() {
        return sort(getInstanceRewards(), on(PvPArenaPlayerReward.class).getScorePoints(), new Comparator<Integer>() {

            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 != null ? o2.compareTo(o1) : -o1.compareTo(o2);
            }

        });
    }

    public boolean canRewardOpportunityToken(PvPArenaPlayerReward rewardedPlayer) {
        if (rewardedPlayer != null) {
            int rank = getRank(rewardedPlayer.getScorePoints());
            return isSoloArena() && rank == 1 || rank > 2;
        }
        return false;
    }

    public int getRank(int points) {
        int rank = -1;
        for (PvPArenaPlayerReward reward : sortPoints()) {
            if (reward.getScorePoints() >= points) {
                rank++;
            }
        }
        return rank;
    }

    public boolean hasCapPoints() {
        if (isSoloArena() && (maxFrom(getInstanceRewards()).getPoints() - minFrom(getInstanceRewards()).getPoints() >= 1500))
            return true;
        return maxFrom(getInstanceRewards()).getPoints() >= capPoints;
    }

    public int getTotalPoints() {
        return sum(getInstanceRewards(), on(PvPArenaPlayerReward.class).getScorePoints());
    }

    public boolean canRewarded() {
        return mapId == 300350000 || mapId == 300360000 || mapId == 300550000 || mapId == 300450000;
    }

    public int getNpcBonusSkill(int npcId) {
        switch (npcId) {
            case 701175: // Plaza Flame Thrower
            case 701176:
            case 701177:
            case 701178:
                return 0x4E5732; // 20055 50
            case 701189: // Plaza Flame Thrower
            case 701190:
            case 701191:
            case 701192:
                return 0x4FDB3C; // 20443 60
            case 701317: // Illusion of Hope level 47
                return 0x4f8532; // 20357 50
            case 701318: // Illusion of Hope level 51
                return 0x4f8537; // 20357 55
            case 701319: // Illusion of Hope level 56
                return 0x4f853C; // 20357 60
            case 701220: // Blesed Relic
                return 0x4E5537; //20053 55 //20068, 20072
            case 207118:
            case 207119:
                return 0x50C101; // 20673 1
            case 207100:
                return 0x50BE01; // 20670 1
            default:
                return 0;
        }
    }

    public int getTime() {
        long result = System.currentTimeMillis() - instanceTime;
        if (isRewarded()) {
            return 0;
        }
        if (result < 120000) {
            return (int) (120000 - result);
        } else {
            return (int) (180000 * getRound() - (result - 120000));
        }
    }

    public void setInstanceStartTime() {
        this.instanceTime = System.currentTimeMillis();
    }

    public void sendPacket() {
        final List<Player> players = instance.getPlayersInside();
        instance.doOnAllPlayers(new Visitor<Player>() {

            @Override
            public void visit(Player player) {
                PacketSendUtility.sendPacket(player, new SM_INSTANCE_SCORE(getTime(), getInstanceReward(), players));
            }

        });
    }

    public byte getBuffId() {
        return buffId;
    }

    @Override
    public void clear() {
        super.clear();
        positions.clear();
    }

}